package com.thh.es.service.impl;

import com.alibaba.fastjson.JSON;
import com.thh.es.entity.FileSearchInfo;
import com.thh.es.mapper.FileSearchInfoMapper;
import com.thh.es.service.FileSearchService;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @description:
 * @author: thh
 * @time: 2020/5/26 21:57
 */
@Service
public class FileSearchServiceImpl implements FileSearchService {

    @Autowired
   private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired
   private FileSearchInfoMapper fileSearchInfoMapper;

    @Override
    public void importData() {
        List<FileSearchInfo> searchInfoList = new ArrayList<>();
        FileSearchInfo fileSearchInfo =  new FileSearchInfo();
        fileSearchInfo.setId("1");
        fileSearchInfo.setContent("河北好声音，世界来聆听。5月25日20时，十三届全国人大三次会议河北代表团以视频形式举行新闻发布会。河北代表团新闻发言人，全国人大代表，保定市委书记、省发改委主任党晓龙发布有关新闻，并就媒体关切的热点问题答记者问。");
        fileSearchInfo.setFileName("河北文件");
        fileSearchInfo.setModifyDate(new Date());
        fileSearchInfo.setModifyUser("张三");
        fileSearchInfo.setFilePath("C:/111/111");



        FileSearchInfo fileSearchInfo2 =  new FileSearchInfo();
        fileSearchInfo2.setId("2");
        fileSearchInfo2.setContent("2003年爆发的伊拉克战争是一场武器装备相差悬殊的战役，美国几乎对伊拉克进行了降维式的打击。仅仅一个多月，这场战役就以美国的胜利而告终。\n" +
                "在战争过程中，除了不出人意料的战争局势发展外，或许最令人感到有趣的，就是当时伊拉克的新闻部长——萨哈夫");
        fileSearchInfo2.setFileName("伊拉克战争");
        fileSearchInfo2.setModifyDate(new Date());
        fileSearchInfo2.setModifyUser("李四");
        fileSearchInfo2.setFilePath("D:111/23");
        searchInfoList.add(fileSearchInfo);
        searchInfoList.add(fileSearchInfo2);
        fileSearchInfoMapper.saveAll(searchInfoList);
    }

    @Override
    public Map<String, Object> search(Map<String, String> searchMap) {

// 1.构建检索条件(后期有多个条件检索，因此我们专门封装一个方法)
        NativeSearchQueryBuilder builder = builderBasicQuery(searchMap);
        // 2.根据关键字搜索列表
        Map<String, Object> resultMap = searchList(builder);
        //3.组合查询
        Long totalElements = (Long) resultMap.get("totalElements");
        // Map<String, Object> groupMap = searchByGroupList(builder, totalElements.intValue());
        // resultMap.putAll(groupMap);
        NativeSearchQuery build = builder.build();
        Pageable pageable = build.getPageable();

        int pageNumber = pageable.getPageNumber();
        int pageSize = pageable.getPageSize();

        resultMap.put("pageNum",pageNumber+1);//当前页
        resultMap.put("pageSize",pageSize);//页面大小


        return resultMap;
    }

    /**
     * 基础搜索
     * @param searchMap
     * @return
     */
    private NativeSearchQueryBuilder builderBasicQuery(Map<String, String> searchMap) {
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        //构建布尔查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //当前页
        String pageNum =  "";
        //当前页面大小
        String pageSize = "";

        if (searchMap != null ) {
            //(1)获取关键字
            String keywords = searchMap.get("keywords");
            if (!StringUtils.isEmpty(keywords)) {
                nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(keywords,"fileName","content"));
                // boolQueryBuilder.must(QueryBuilders.multiMatchQuery(keywords,"achievementName","keyTechnologiesInfo").operator(Operator.AND));
            }


            //添加过滤
            nativeSearchQueryBuilder.withFilter(boolQueryBuilder);

            pageNum = searchMap.get("pageNum");
            pageSize = searchMap.get("pageSize");
        }
        //排序
        nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("modifyDate").order(SortOrder.DESC));

        //6.分页


        int page = 1;
        int size = 5;
        if (!StringUtils.isEmpty(pageNum)) {

            page = Integer.valueOf(pageNum);
            if (page<0){
                page=1;
            }
        }

        if (!StringUtils.isEmpty(pageSize)) {
            size = Integer.valueOf(pageSize);
        }
        Pageable pageable = PageRequest.of(page - 1, size);
        nativeSearchQueryBuilder.withPageable(pageable);




        return nativeSearchQueryBuilder;
    }


    private Map<String, Object> searchList(NativeSearchQueryBuilder builder) {
        //设置高亮显示的条件
        HighlightBuilder.Field field1 = new HighlightBuilder.Field("name");
        field1.preTags("<font color='red'>"); //高亮字段前缀
        field1.postTags("</font>");  //高亮字段后缀
        // field1.fragmentOffset(100);//截断字数

        HighlightBuilder.Field field2 = new HighlightBuilder.Field("content");
        field2.preTags("<font color='red'>"); //高亮字段前缀
        field2.postTags("</font>");  //高亮字段后缀
        //field2.fragmentOffset(100);//截断字数


        builder.withHighlightFields(field1,field2); //添加高亮条件


        SearchResultMapper searchResultMapper = new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                //结果集处理
                SearchHits hits = searchResponse.getHits();
                //封装结果集
                List<FileSearchInfo> content = new ArrayList<>();
                if (hits!=null && hits.totalHits>0){
                    for (SearchHit hit : hits) {

                        String text = hit.getSourceAsString(); // json格式的字符串
                        FileSearchInfo searchInfo = JSON.parseObject(text, FileSearchInfo.class);//普通结果
                        HighlightField highlightField = hit.getHighlightFields().get("fileName");

                        HighlightField highlightField2 = hit.getHighlightFields().get("content");


                        if (highlightField!=null){
                            Text[] fragments = highlightField.getFragments();
                            String highLightName = fragments[0].toString();
                            //将普通字段替换成高亮的名称
                            searchInfo.setFileName(highLightName);

                        }

                        if (highlightField2!=null){
                            Text[] fragments2 = highlightField2.getFragments();
                            String highLightName2 = fragments2[0].toString();
                            //将普通字段替换成高亮的名称
                            searchInfo.setContent(highLightName2);

                        }

                        content.add(searchInfo);

                    }
                }

                return new AggregatedPageImpl<>((List<T>) content,pageable,hits.getTotalHits());
            }
        };

        NativeSearchQuery build = builder.build();
        AggregatedPage<FileSearchInfo> page = elasticsearchTemplate.queryForPage(build, FileSearchInfo.class,searchResultMapper);
        List<FileSearchInfo> rows = page.getContent();//list结果集
        int totalPages = page.getTotalPages();//总页数
        long totalElements = page.getTotalElements();//总条数
        //封装结果集
        Map<String, Object> map = new HashMap<>();
        map.put("rows", rows);
        map.put("totalPages", totalPages);
        map.put("totalElements", totalElements);

        return map;
    }
}
